package com.example.game2048;

import static com.example.game2048.annotation.GridType.GRID_SCALE;

import com.example.game2048.bean.Pile;
import com.example.game2048.bean.Position;
import com.example.game2048.module.ConfigPosition;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * Grid 网格类，存储当前网格的状态
 */
public class Grid {
    private List<Position> positionList = new ArrayList<>();

    public int getScore() {
        return score;
    }

    private int score;

    public void initGrid(int n,int pileSize){
        score = 0;
        for(int y=0;y<n;y++)
            for(int x=0;x<n;x++)
                positionList.add(new Position(x*pileSize,y*pileSize));
        ConfigPosition.config(positionList);

        createRandomPile();
        createRandomPile();
    }


    public List<Pile> getPileList(){
        List<Pile> pileList = new ArrayList<>();
        for (Position position : positionList) {
            if(position.getPile() != null)
                pileList.add(position.getPile());
        }
        return pileList;
    }
    public List<Position> getUnEmptyPositionList(){
        return positionList
                .stream()
                .filter(position -> position.getPile()!=null)
                .collect(Collectors.toList());
    }
    public boolean insertNewPile(){
        int emptyPositionNum = getEmptyPileNum();
        if(emptyPositionNum!=0){
            createRandomPile();
            return true;
        }else {
            return false;
        }
    }

    private void createRandomPile(){
        int emptyPositionNum = getEmptyPileNum();
        if(emptyPositionNum != 0){
              Random random = new Random();
              int randomIndex = random.nextInt(emptyPositionNum);
              Position randomPosition = skipIndexAndGetEmptyPosition(randomIndex);
              if(randomPosition!=null){
                  randomPosition.setPile(new Pile(2));
                  ConfigPosition.setOriginPositionOfPile(randomPosition);
              }
        }
    }

    private int getEmptyPileNum(){
        return (int)positionList.stream()
                .filter(position -> position.getPile()==null)
                .count();
    }

    private Position skipIndexAndGetEmptyPosition(int index){
        return positionList.stream()
                .filter(position -> position.getPile()==null)
                .skip(index)
                .limit(1)
                .findFirst()
                .orElse(null);
    }

    public void rightMotion(){
        for(int row=0;row< GRID_SCALE;row++){
            for(int column=GRID_SCALE-1;column>=0;column--){
                Position position = getGridPosition(row,column);
                if(position.getPile() != null)
                    moveRight(position);
            }
        }
    }
    //如果能移动，继续判断；如果不能移动，结束判断
    /*TODO:movexxx大多数操作都是一样的，只有getxxxPosition这个不一样
        但这是一个动作，不能考传递参数解决。用函数式应该可以传递操作之类的？*/
    private void moveRight(Position position){
        while(true){
            Position rightPosition = position.getRightPosition();
            if(rightPosition == null)
                return;
            if(rightPosition.getPile() == null){
                position = movePile(position,rightPosition);
                continue;
            }
            if(rightPosition.getPile().getValue() == position.getPile().getValue()) {
                position = mergePile(position, rightPosition);
                continue;
            }
            return;
        }
    }

    public void leftMotion(){
        for(int row=0;row< GRID_SCALE;row++){
            for(int column=0;column< GRID_SCALE;column++){
                Position position = getGridPosition(row,column);
                if(position.getPile() != null)
                    moveLeft(position);
            }
        }
    }
    private void moveLeft(Position position){
        while(true){
            Position leftPosition = position.getLeftPosition();
            if(leftPosition == null)
                return;
            if(leftPosition.getPile() == null){
                position = movePile(position,leftPosition);
                continue;
            }
            if(leftPosition.getPile().getValue() == position.getPile().getValue()) {
                position = mergePile(position, leftPosition);
                continue;
            }
            return;
        }
    }

    public void upMotion(){
        //只需要保证从上到下，左右无所谓
        for(int row=0;row< GRID_SCALE;row++){
            for(int column=0;column< GRID_SCALE;column++){
                Position position = getGridPosition(row,column);
                if(position.getPile() != null)
                    moveUp(position);
            }
        }
    }
    private void moveUp(Position position){
        while(true){
            Position leftPosition = position.getTopPosition();
            if(leftPosition == null)
                return;
            if(leftPosition.getPile() == null){
                position = movePile(position,leftPosition);
                continue;
            }
            if(leftPosition.getPile().getValue() == position.getPile().getValue()) {
                position = mergePile(position, leftPosition);
                continue;
            }
            return;
        }
    }

    public void downMotion(){
        for(int row=GRID_SCALE-1;row>=0;row--){
            for(int column=0;column< GRID_SCALE;column++){
                Position position = getGridPosition(row,column);
                if(position.getPile() != null)
                    moveDown(position);
            }
        }
    }
    private void moveDown(Position position){
        while(true){
            Position leftPosition = position.getBottomPosition();
            if(leftPosition == null)
                return;
            if(leftPosition.getPile() == null){
                position = movePile(position,leftPosition);
                continue;
            }
            if(leftPosition.getPile().getValue() == position.getPile().getValue()) {
                position = mergePile(position, leftPosition);
                continue;
            }
            return;
        }
    }

    private Position getGridPosition(int row,int column){
        return positionList.get(row*GRID_SCALE+column);
    }
    //注意移动之后就要以新的位置为基准重新移动，否则原来的position中pile为空，会出现空指针
    private Position movePile(Position oldPosition,Position newPosition){
        newPosition.setPile(oldPosition.getPile());
        newPosition.getPile().setMove(true);
        oldPosition.setPile(null);
        return newPosition;
    }
    private Position mergePile(Position oldPosition,Position newPosition){
        movePile(oldPosition,newPosition);
        newPosition.getPile().setValue(newPosition.getPile().getValue()*2);
        score += newPosition.getPile().getValue();
        newPosition.getPile().setJoined(true);
        return newPosition;
    }
}
